/*
 ------------------------------------------------------------------------------
	willy-player - a simple music player based on SDL.

	Copyright (C) 2011 Pierre Veber
	
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 3 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software Foundation,
	Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

	Note: 
	this code uses code from CoolPlayer - Blazing fast audio player.
	Copyright (C) 2000-2001 Niek Albers  
	MPEG Audio codec (using MAD)  
	Copyright (C) 2001 Robert Leslie 
	http://coolplayer.sourceforge.net/
 ------------------------------------------------------------------------------
*/

#include "../precomp.h"
#include "../depends/mad/mad.h"
#include "../depends/mad/id3tag.h"

/* libid3tag unexported definitions */
# ifdef __cplusplus
extern "C" {
# endif
id3_length_t id3_ucs4_utf16size(id3_ucs4_t const *);
id3_length_t id3_ucs4_length(id3_ucs4_t const *);
void id3_utf16_encode(id3_utf16_t *, id3_ucs4_t const *);
# ifdef __cplusplus
}
# endif

#define MadErrorString(x) mad_stream_errorstr(x)
#define INPUT_BUFFER_SIZE	8192

#define MAD_EMPTY		0
#define MAD_PREPARED	1
#define MAD_DECODING	2

/*
	From CoolPlayer MPEG audio codec [BEGIN]
*/
#define SAMPLE_DEPTH 16
#define scale(x, y) dither((x), (y))
#define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')

struct xing_t
{
	long flags;
	unsigned long frames;
	unsigned long bytes;
	unsigned char toc[100];
	long scale;
};

enum
{
	XING_FRAMES = 0x00000001L,
	XING_BYTES  = 0x00000002L,
	XING_TOC    = 0x00000004L,
	XING_SCALE  = 0x00000008L
};

struct dither
{
	mad_fixed_t error[3];
	mad_fixed_t random;
};

/*
 * NAME:  prng()
 * DESCRIPTION: 32-bit pseudo-random number generator
 */
static __inline
unsigned long prng(unsigned long state)
{
	return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
}

/*
 * NAME:  dither()
 * DESCRIPTION: dither and scale sample
 */
static __inline
signed int dither(mad_fixed_t sample, struct dither *dither)
{
	unsigned int scalebits;
	mad_fixed_t output, mask, random;
	
	enum
	{
		MIN = -MAD_F_ONE,
		MAX =  MAD_F_ONE - 1
	};
	
	/* noise shape */
	sample += dither->error[0] - dither->error[1] + dither->error[2];
	
	dither->error[2] = dither->error[1];
	dither->error[1] = dither->error[0] / 2;
	
	/* bias */
	output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
	
	scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
	mask = (1L << scalebits) - 1;
	
	/* dither */
	random  = prng(dither->random);
	output += (random & mask) - (dither->random & mask);
	
	dither->random = random;
	
	/* clip */
	
	if (output > MAX)
	{
		output = MAX;
		
		if (sample > MAX)
			sample = MAX;
	}
	
	else if (output < MIN)
	{
		output = MIN;
		
		if (sample < MIN)
			sample = MIN;
	}
	
	/* quantize */
	output &= ~mask;
	
	/* error feedback */
	dither->error[0] = sample - output;
	
	/* scale */
	return output >> scalebits;
}

/*
 * NAME:  parse_xing()
 * DESCRIPTION: read a Xing VBR tag
 */
static
int parse_xing(struct xing_t *xing, struct mad_bitptr ptr, unsigned int bitlen)
{
	if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC)
		goto fail;
		
	xing->flags = mad_bit_read(&ptr, 32);
	
	bitlen -= 64;
	
	if (xing->flags & XING_FRAMES)
	{
		if (bitlen < 32)
			goto fail;
			
		xing->frames = mad_bit_read(&ptr, 32);
		
		bitlen -= 32;
	}
	
	if (xing->flags & XING_BYTES)
	{
		if (bitlen < 32)
			goto fail;
			
		xing->bytes = mad_bit_read(&ptr, 32);
		
		bitlen -= 32;
	}
	
	if (xing->flags & XING_TOC)
	{
		int i;
		
		if (bitlen < 800)
			goto fail;
			
		for (i = 0; i < 100; ++i)
			xing->toc[i] = (unsigned char) mad_bit_read(&ptr, 8);
			
		bitlen -= 800;
	}
	
	if (xing->flags & XING_SCALE)
	{
		if (bitlen < 32)
			goto fail;
			
		xing->scale = mad_bit_read(&ptr, 32);
		
		bitlen -= 32;
	}
	
	return 0;
	
fail:
	xing->flags = 0;
	return -1;
}

/*
	From CoolPlayer MPEG audio codec [END]
*/

static int _id3_utf16_eq(Uint16* p1, Uint16* p2)
{
	while ( (*p1 != 0) && (*p2 != 0) )
	{
		if (*p1++ != *p2++)
		{
			return 0;
		}
	}
	return 1;
}

static int _id3_get_utf16_value(id3_frame* pID3Frame, Uint16** ppVal, MallocProc fpMalloc, void* pData)
{
	const id3_ucs4_t* pUCS4 = NULL;
	int nSize, nLen = 0;

	for (unsigned int ui=0; (ui < pID3Frame->nfields) && (pUCS4 == NULL); ui++)
	{
		id3_field* pID3Field = id3_frame_field(pID3Frame, ui);
		switch (id3_field_type(pID3Field))
		{
			case ID3_FIELD_TYPE_STRINGLIST:
				pUCS4 = id3_field_getstrings(pID3Field, 0);
				break;

			case ID3_FIELD_TYPE_STRING:
				pUCS4 = id3_field_getstring(pID3Field);
				break;

			default:
				break;
		}
	}

	if (pUCS4 != NULL)
	{
		nSize = id3_ucs4_utf16size(pUCS4);
		*ppVal = (Uint16*)fpMalloc(nSize*sizeof(Uint16), pData);
		if (*ppVal != NULL)
		{
			id3_utf16_encode(*ppVal, pUCS4);
			nLen = id3_ucs4_length(pUCS4);
		}
	}
		
	return nLen;
}

int seek;

class CWPMadDecoder : public CWPDecoder
{
public:

	CWPMadDecoder();
	virtual ~CWPMadDecoder();

	/* decoder information functions */
	virtual const char* name() 			{ return "Mad"; } ;
	virtual const char* extensions()	{ return "mp3"; } ;

	/* decoding functions */
	virtual int prepare(char* lpszFileToDecode);
	virtual int decode();
	virtual int pause();
	virtual int stop();
	virtual int seek(int);
	
	/* file information (tag) function */
	virtual int getInfo(AudioFile_t*, MallocProc, void*);
	virtual SDL_Surface* getPicture(AudioFile_t*);

private:
	char*				pszFilePath;
	FILE*				fpTrack;
	
	struct mad_stream	Stream;
	struct mad_frame	Frame;
	struct mad_synth	Synth;
	struct xing_t		Xing;
	mad_timer_t			Timer;
	mad_timer_t			Length;
	size_t				Size;
	unsigned char		InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
	unsigned char*		GuardPtr;
	int					Status;
	int					FramesToMute;
	unsigned long		FrameCount;
};

CWPMadDecoder MadDecoder;
CWPDecoder* _g_pMadDecoder = (CWPDecoder*)&MadDecoder;

CWPMadDecoder::CWPMadDecoder(void) : CWPDecoder()
{
	this->FramesToMute = 0;
	this->FrameCount = 0;
	this->GuardPtr = NULL;
	this->Status = MAD_EMPTY;
	this->pszFilePath = NULL;
	memset(&(this->Xing), 0, sizeof(xing_t));
}

int CWPMadDecoder::prepare(char * pszFile)
{
	unsigned char id3_header[10];
	size_t start = 0;

	if (this->hAudio == NULL)
	{
		TRACE("Called CWPMadDecoder::prepare without prior call to setAudioDevice (hAudio == NULL)");
		return -1;
	}

	if (this->Status != MAD_EMPTY)
	{
		/* stop decoding */
		this->stop();
	}

	if (this->pszFilePath != NULL)
	{
		free(this->pszFilePath);
	}
	this->pszFilePath = _strdup(pszFile);
	
	/* open the file for reading */
	this->fpTrack = fopen(pszFile, "rb");
	if (this->fpTrack == NULL)
	{
		TRACE1("Unable to open: %s!", pszFile);
		free(this->pszFilePath);
		this->pszFilePath = NULL;
		return -1;
	}
	fseek(this->fpTrack , 0, SEEK_END);
	this->Size = ftell(this->fpTrack);
	fseek(this->fpTrack, 0, SEEK_SET);

	/* header skip/read */
	if (
			fread(&id3_header, sizeof(unsigned char), 10, this->fpTrack)
		 && ( (id3_header[0] == 'I') && (id3_header[1] == 'D') && (id3_header[2] == '3') )	)
	{
		start = (id3_header[6] << 21) + (id3_header[7] << 14) + (id3_header[8] << 7) + id3_header[9];
	}
	fseek(this->fpTrack, start, SEEK_SET);

	mad_stream_init(&Stream);
	mad_frame_init(&Frame);
	mad_synth_init(&Synth);
	mad_timer_reset(&Timer);
	mad_timer_reset(&Length);

	this->FramesToMute = 0;
	this->FrameCount = 0;
	this->GuardPtr = NULL;
	this->Status = MAD_PREPARED;
	memset(&(this->Xing), 0, sizeof(xing_t));

	return 0;
}

/*	one iteration of a decoding loop. This function is called by the player
	as long as there are e.g. no stop/pause commands */
int CWPMadDecoder::decode(void)
{
	int i, rc;
	char OutputBuffer[4];

	if (this->Status == MAD_EMPTY)
	{
		TRACE("Called CWPMadDecoder::decode without prior call to prepare (Status == MAD_EMPTY)");
		return -1;
	}
	else if (this->Status == MAD_PREPARED)
	{
		this->Status = MAD_DECODING;
	}

	/* The input bucket must be filled if it becomes empty or if
	 * it's the first execution of the loop.
	 */
	if ( (Stream.buffer == NULL) || (Stream.error == MAD_ERROR_BUFLEN) )
	{
		size_t			ReadSize,
						Remaining;
		unsigned char	*ReadStart;

		/* {2} libmad may not consume all bytes of the input
		 * buffer. If the last frame in the buffer is not wholly
		 * contained by it, then that frame's start is pointed by
		 * the next_frame member of the Stream structure. This
		 * common situation occurs when mad_frame_decode() fails,
		 * sets the stream error code to MAD_ERROR_BUFLEN, and
		 * sets the next_frame pointer to a non NULL value. (See
		 * also the comment marked {4} bellow.)
		 *
		 * When this occurs, the remaining unused bytes must be
		 * put back at the beginning of the buffer and taken in
		 * account before refilling the buffer. This means that
		 * the input buffer must be large enough to hold a whole
		 * frame at the highest observable bit-rate (currently 448
		 * kb/s). XXX=XXX Is 2016 bytes the size of the largest
		 * frame? (448000*(1152/32000))/8
		 */
		if (Stream.next_frame != NULL)
		{
			Remaining = Stream.bufend - Stream.next_frame;
			memmove(InputBuffer, Stream.next_frame, Remaining);
			ReadStart = InputBuffer + Remaining;
			ReadSize = INPUT_BUFFER_SIZE - Remaining;
		}
		else
		{
			ReadSize = INPUT_BUFFER_SIZE;
			ReadStart = InputBuffer;
			Remaining = 0;
		}

		/* Fill-in the buffer. If an error occurs print a message
		 * and leave the decoding loop. If the end of stream is
		 * reached we also leave the loop but the return status is
		 * left untouched.
		 */
		ReadSize = fread(ReadStart, 1, ReadSize, this->fpTrack);
		if ( ReadSize <= 0 )
		{
			if (ferror(this->fpTrack))
			{
				TRACE1("MpegAudioDecoder() - read error on bit-stream (%s)", strerror(errno));
				Status = 1;
			}
			if (feof(this->fpTrack))
			{
				TRACE("MpegAudioDecoder() - end of input stream.");
			}
			return -1;
		}

		/* {3} When decoding the last frame of a file, it must be
		 * followed by MAD_BUFFER_GUARD zero bytes if one wants to
		 * decode that last frame. When the end of file is
		 * detected we append that quantity of bytes at the end of
		 * the available data. Note that the buffer can't overflow
		 * as the guard size was allocated but not used the the
		 * buffer management code. (See also the comment marked
		 * {1}.)
		 *
		 * In a message to the mad-dev mailing list on May 29th,
		 * 2001, Rob Leslie explains the guard zone as follows:
		 *
		 *    "The reason for MAD_BUFFER_GUARD has to do with the
		 *    way decoding is performed. In Layer III, Huffman
		 *    decoding may inadvertently read a few bytes beyond
		 *    the end of the buffer in the case of certain invalid
		 *    input. This is not detected until after the fact. To
		 *    prevent this from causing problems, and also to
		 *    ensure the next frame's main_data_begin pointer is
		 *    always accessible, MAD requires MAD_BUFFER_GUARD
		 *    (currently 8) bytes to be present in the buffer past
		 *    the end of the current frame in order to decode the
		 *    frame."
		 */
		if (feof(this->fpTrack))
		{
			GuardPtr = ReadStart + ReadSize;
			memset(GuardPtr, 0, MAD_BUFFER_GUARD);
			ReadSize += MAD_BUFFER_GUARD;
		}

		/* Pipe the new buffer content to libmad's stream decoder
         * facility.
		 */
		mad_stream_buffer(&Stream, InputBuffer, ReadSize+Remaining);
		Stream.error = (mad_error)0;
	}
	
	/* Decode the next MPEG frame. The streams is read from the
	 * buffer, its constituents are break down and stored the the
	 * Frame structure, ready for examination/alteration or PCM
	 * synthesis. Decoding options are carried in the Frame
	 * structure from the Stream structure.
	 *
	 * Error handling: mad_frame_decode() returns a non zero value
	 * when an error occurs. The error condition can be checked in
	 * the error member of the Stream structure. A mad error is
	 * recoverable or fatal, the error status is checked with the
	 * MAD_RECOVERABLE macro.
	 *
	 * {4} When a fatal error is encountered all decoding
	 * activities shall be stopped, except when a MAD_ERROR_BUFLEN
	 * is signaled. This condition means that the
	 * mad_frame_decode() function needs more input to complete
	 * its work. One shall refill the buffer and repeat the
	 * mad_frame_decode() call. Some bytes may be left unused at
	 * the end of the buffer if those bytes forms an incomplete
	 * frame. Before refilling, the remaining bytes must be moved
	 * to the beginning of the buffer and used for input for the
	 * next mad_frame_decode() invocation. (See the comments
	 * marked {2} earlier for more details.)
	 *
	 * Recoverable errors are caused by malformed bit-streams, in
	 * this case one can call again mad_frame_decode() in order to
	 * skip the faulty part and re-sync to the next frame.
	 */
	if (mad_frame_decode(&Frame, &Stream))
	{
		if (MAD_RECOVERABLE(Stream.error))
		{
			/* Do not print a message if the error is a loss of
			 * synchronization and this loss is due to the end of
			 * stream guard bytes. (See the comments marked {3}
			 * supra for more informations about guard bytes.)
			 */
			if ( (Stream.error != MAD_ERROR_LOSTSYNC) || (Stream.this_frame != GuardPtr) )
			{
				TRACE1("MpegAudioDecoder() - recoverable frame level error (%s)", MadErrorString(&Stream));
			}
			return 0;
		}
		else
		{
			if (Stream.error == MAD_ERROR_BUFLEN)
			{
				return 0;
			}
			else
			{
				TRACE1("MpegAudioDecoder() - unrecoverable frame level error (%s).", MadErrorString(&Stream));
				Status = 1;
				return -1;
			}
		}
	}

	if (FrameCount == 0)
	{
		
		/* First frame can be a XING frame (VBR info) */
		if (	(parse_xing(&(this->Xing), Stream.anc_ptr, Stream.anc_bitlen) == 0)
			 && (this->Xing.flags & XING_FRAMES)	)
		{
			/* in this case duration is computed with the number of frames */
			Length = Frame.header.duration;
			mad_timer_multiply(&Length, this->Xing.frames);
			/* no accounting of time */
		}
		else
		{
			/* CBR - compute length from bitrate */
			mad_timer_set(&Length, 0, 1, Frame.header.bitrate / 8);
			mad_timer_multiply(&Length, Size);
			/* time accounting */
			mad_timer_add(&Timer, Frame.header.duration);
		}
	}
	else
	{
		/* time accounting */
		mad_timer_add(&Timer, Frame.header.duration);
	}
	FrameCount++;

	/* Once decoded the frame is synthesized to PCM samples. No errors
	 * are reported by mad_synth_frame();
	 */
	if (FramesToMute == 0)
	{
		/* Only if frame has not to be muted */
		mad_synth_frame(&Synth, &Frame);

		/* Synthesized samples must be converted from libmad's fixed
		 * point number to the consumer format. Here we use unsigned
		 * 16 bit big endian integers on two channels. Integer samples
		 * are temporarily stored in a buffer that is flushed when
		 * full.
		 */
		for (i=0; i < Synth.pcm.length; i++)
		{
			signed int Sample;
			static struct dither d0, d1;

			/* Left channel */
			Sample = scale(Synth.pcm.samples[0][i], &d0);
			OutputBuffer[0] = (Sample >> 0) & 0xff;
			OutputBuffer[1] = (Sample >> 8) & 0xff;

			/* Right channel. If the decoded stream is monophonic then
			 * the right output channel is the same as the left one.
			 */
			if (MAD_NCHANNELS(&Frame.header) == 2)
			{
				Sample = scale(Synth.pcm.samples[1][i], &d1);
			}
			OutputBuffer[2] = (Sample >> 0) & 0xff;
			OutputBuffer[3] = (Sample >> 8) & 0xff;

			rc = waveWriteIn(this->hAudio, OutputBuffer, 1);
		}
	}
	else
	{
		/* if frames have to be muted, decrement counter */
		FramesToMute--;
	}

	return 0;
}

int CWPMadDecoder::pause(void)
{
	return 0;
}

int CWPMadDecoder::stop(void)
{
	mad_synth_finish(&Synth);
	mad_frame_finish(&Frame);
	mad_stream_finish(&Stream);

	if (this->fpTrack != NULL)
	{
		fclose(this->fpTrack);
	}
	if (this->pszFilePath != NULL)
	{
		free(this->pszFilePath);
	}
	this->pszFilePath = NULL;
	this->fpTrack = NULL;
	this->Status = MAD_EMPTY;

	return 0;
}

int CWPMadDecoder::seek(int amt)
{
	double fraction;
	unsigned long position;
	
	fraction = (double)amt / 100.0;
	position = (unsigned long)(mad_timer_count(Length, MAD_UNITS_MILLISECONDS) * fraction);
	mad_timer_set(&Timer, position / 1000, position % 1000, 1000);
	fseek(this->fpTrack, (long)(Size * fraction), SEEK_SET);
	size_t ReadSize = fread(InputBuffer, 1, INPUT_BUFFER_SIZE, this->fpTrack);
	if ( ReadSize <= 0 )
	{
		if (ferror(this->fpTrack))
		{
			TRACE1("MpegAudioDecoder() - read error on bit-stream (%s)",strerror(errno));
			Status = 1;
		}
		if (feof(this->fpTrack))
		{
			TRACE("MpegAudioDecoder() - end of input stream\n");
		}
		return -1;
	}

	mad_stream_buffer(&Stream, InputBuffer, ReadSize);
	mad_frame_mute(&Frame);	
	mad_synth_mute(&Synth);
	
	FramesToMute = 4;
	
	return 0;
}

int CWPMadDecoder::getInfo(AudioFile_t* pFile, MallocProc fp = NULL, void* pData = NULL)
{
	id3_file* pID3File;
	id3_tag* pID3Tag;
	id3_frame* pID3Frame;

	/* get ID3 tags */
	pID3File = id3_file_open(pFile->pszFullPath, ID3_FILE_MODE_READONLY);
	if (pID3File == 0)
	{
		TRACE1("_id3_get_info() - Unable to open id3: %S !\n", pszFilePath);
		return -1;
	}

	pID3Tag = id3_file_tag(pID3File);
	for (int i=0; i < (int)pID3Tag->nframes; i++)
	{
		pID3Frame = pID3Tag->frames[i];
		if (strcmp("TIT2", pID3Frame->id) == 0)
		{
			/* track title */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszTrack), fp, pData);
			continue;
		}
		if (strcmp("TALB", pID3Frame->id) == 0)
		{
			/* album title */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszAlbum), fp, pData);
			continue;
		}
		if (strcmp("TRCK", pID3Frame->id) == 0)
		{
			/* track number */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszTrackNum), fp, pData);
			continue;
		}
		if (strcmp("TPE1", pID3Frame->id) == 0)
		{
			/* artist name */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszArtist), fp, pData);
			continue;
		}
		if (strcmp("TLEN", pID3Frame->id) == 0)
		{
			/* length of track in ms */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszMsLength), fp, pData);
			continue;
		}
		if (	(strcmp("TDRC", pID3Frame->id) == 0)
			 || (strcmp("TYER", pID3Frame->id) == 0)	)
		{
			/* release date */
			_id3_get_utf16_value(pID3Frame, &(pFile->info.pszYear), fp, pData);
			continue;
		}
		/*
			To do:
				RVA2?
				EQU2?
				RBUF?
				ASPI
		*/
	}

	id3_file_close(pID3File);

	return 0;
}

SDL_Surface* CWPMadDecoder::getPicture(AudioFile_t* pFile)
{
	id3_file* pID3File;
	id3_tag* pID3Tag;
	id3_frame* pID3Frame;
	id3_field* pBinary;
	
	SDL_Surface* pOut = NULL;

	/* get ID3 tags */
	pID3File = id3_file_open(pFile->pszFullPath, ID3_FILE_MODE_READONLY);
	if (pID3File == NULL)
	{
		TRACE1("_id3_get_album_picture() - Unable to open id3: %S !\n", pszFilePath);
		return NULL;
	}

	pID3Tag = id3_file_tag(pID3File);
	if (pID3Tag == NULL)
	{
		TRACE1("_id3_get_album_picture() - Unable to get id3 tag in %S !\n", pszFilePath);
		id3_file_close(pID3File);
		return NULL;
	}

	pID3Frame = id3_tag_findframe(pID3Tag, "APIC", pID3Tag->nframes);
	if ( (pID3Frame == NULL) || (pID3Frame->nfields < 5) )
	{
		TRACE1("_id3_get_album_picture() - Unable to get id3 tag in %S !\n", pszFilePath);
		id3_file_close(pID3File);
		return NULL;
	}

	/* picture type */
	if (id3_field_getint(id3_frame_field(pID3Frame, 2)) == 3)
	{
		/* check mime type */
		const unsigned char* pszMime = id3_field_getlatin1(id3_frame_field(pID3Frame, 1));
		if (	(strcmp((const char *)pszMime, "image/png") != 0)
			 && (strcmp((const char *)pszMime, "image/jpeg") != 0)	)
		{
			TRACE2("_id3_get_album_picture() - unsupported image format %S in %S!\n", (const char*)pszMime, pszFilePath);
			id3_file_close(pID3File);
			return NULL;
		}

		/* binary data */
		pBinary = id3_frame_field(pID3Frame, 4);
		if (pBinary != NULL)
		{
			SDL_RWops* pOps = SDL_RWFromConstMem(pBinary->binary.data, pBinary->binary.length);
			if (pOps != NULL)
			{
				pOut = IMG_Load_RW(pOps, 1);
			}
		}
	}

	id3_file_close(pID3File);
	return pOut;
}

CWPMadDecoder::~CWPMadDecoder(void)
{
	if (this->fpTrack != NULL)
	{
		fclose(this->fpTrack);
	}
	if (this->pszFilePath != NULL)
	{
		free(this->pszFilePath);
	}
}